<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick, watch, useSlots } from "vue";
import { templateRef, promiseTimeout } from "@vueuse/core";
import { useECharts } from "@pureadmin/utils";
import { useIsEchartsOptionNotEmpty } from "@/hooks/useEcharts";
import type { LabelLayoutFunctionType, EchartsInstanceFunctionType } from "../types";
import type { ECharts } from "echarts";
import { emitter } from "@/utils/mitt";

const theme = computed(() => (props.dark ? "dark" : "light"));

interface Props {
  /**  获取当前echarts实例对象，参数为实例对象和回调函数 */
  getEchartsInstance?: EchartsInstanceFunctionType | null;
  /**  获取 optiins 配置函数 */
  labelLayoutFn?: LabelLayoutFunctionType | null;
  /**  同 echarts option */
  options?: CommonEcharts.CommonEchartsOption | null;
  /**  同 px-empty image-size */
  imageSize?: number;
  /**  是否dark模式 */
  dark?: boolean;
  /**  是否根据 series data 判断是否渲染echarts，默认true */
  isSeriesDataRender?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  imageSize: 80,
  dark: false,
  isSeriesDataRender: true
});

const slot = useSlots();
const echartsRef = ref<string>(`echartsCom_${Math.random().toString(36).slice(2, 10)}`);
const echartsObject = ref<any>(null);
const fnOptions = ref<CommonEcharts.CommonEchartsOption>(null);

const isShowEcharts = computed(() => {
  if (props.labelLayoutFn) {
    return useIsEchartsOptionNotEmpty(fnOptions.value, props.isSeriesDataRender);
  } else {
    return useIsEchartsOptionNotEmpty(props.options, props.isSeriesDataRender);
  }
});

const getEcharts = async (): Promise<any> => {
  if (echartsObject.value) return echartsObject.value;
  echartsObject.value = useECharts(templateRef(echartsRef.value), { theme: theme.value });
  await nextTick();
  return echartsObject.value;
};

const updateData = async (options: CommonEcharts.CommonEchartsOption): Promise<ECharts> => {
  await nextTick();
  if (!echartsObject.value) return;
  const { resize, getInstance } = echartsObject.value;
  getInstance().setOption(options);
  await nextTick();
  resize();
  return getInstance();
};

const initData = async (flag?: boolean) => {
  await nextTick();
  if (!echartsObject.value) return;
  const { setOptions, clear, resize, getInstance } = echartsObject.value;
  clear();
  if (props.labelLayoutFn) {
    fnOptions.value = await props.labelLayoutFn(echartsObject.value);
    fnOptions.value && (flag ? setOptions(fnOptions.value, flag) : setOptions(fnOptions.value));
  } else {
    props.options && (flag ? setOptions(props.options, flag) : setOptions(props.options));
  }
  await nextTick();
  props.getEchartsInstance && props.getEchartsInstance(getInstance(), (o: CommonEcharts.CommonEchartsOption) => updateData(o));
  resize();
};

const init = async () => {
  await nextTick();
  const { resize = null } = await getEcharts();
  resize && resize();
};

const emitChange = () => {
  emitter.on("toggleMenu", init);
  window.addEventListener("resize", init);
};

const disposeEmitChange = () => {
  window.removeEventListener("resize", init);
  emitter.off("toggleMenu");
};

const updateOption = async (flag: boolean = false) => {
  await nextTick();
  if (!echartsObject.value) return;
  const ins = echartsObject.value?.getInstance();
  if (!ins) return;
  if (props.labelLayoutFn) {
    fnOptions.value = await props.labelLayoutFn(echartsObject.value);
    fnOptions.value && ins.setOption(fnOptions.value, flag);
  } else {
    props.options && ins.setOption(props.options, flag);
  }
};

let flag = true;

const watcher = watch(
  () => props.options,
  async val => {
    if (val && flag) {
      await getEcharts();
      await initData();
      flag = false;
      watcher();
    }
  },
  { immediate: true, deep: true }
);

onMounted(async () => {
  if (!props.options) {
    await getEcharts();
    await initData();
  }
  emitChange();
});

onUnmounted(() => {
  disposeEmitChange();
});

defineExpose({
  echartsRef: templateRef(echartsRef.value),
  echartsObject,
  fnOptions,
  getEcharts,
  initData,
  updateData,
  emitChange,
  disposeEmitChange,
  updateOption,
  isShowEcharts
});
</script>

<template>
  <div class="echarts-content">
    <div :ref="echartsRef" :class="['echarts-com', isShowEcharts ? '' : 'echarts-com-hidden']" />
    <div :class="['echarts-empty', isShowEcharts ? 'echarts-empty-hidden' : '']">
      <px-empty class="px-empty-common" :image-size="imageSize" :dark="dark">
        <template v-if="slot.emptyDefault" #default>
          <slot name="emptyDefault" />
        </template>
      </px-empty>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.echarts-content {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;

  .echarts-com {
    display: block;
    width: 100%;
    height: 100%;
    margin: 0 auto;
  }

  .echarts-com-hidden {
    width: 0;
    height: 0;
    overflow: hidden;
  }

  .echarts-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;

    .px-empty {
      padding: 0;
    }
  }

  .echarts-empty-hidden {
    width: 0;
    height: 0;
    overflow: hidden;
  }
}
</style>
